package com.raymond.algorithm.filterrepeat;


import org.roaringbitmap.longlong.Roaring64Bitmap;

/**
 * bitmap过滤
 * 通过时间滑动窗口过滤
 * 窗口越多，滑动越平滑，效率越慢(推荐:4个窗口，60 * 1000(一分钟))
 *
 * @author :  raymond
 * @version :  V1.0
 * @date :  2021-11-12 14:27
 */
public class BitMapFilter {
    private Roaring64Bitmap[] bitmap;
    /**
     * 切割的窗口个数
     */
    private int split;
    /**
     * 滑动时间
     * 每个窗口的数据存活时间
     */
    private int slidingTime;
    /**
     * 时间窗口下标
     */
    private long index;
    /**
     * 记录每个窗口的条数
     */
    private long[] splitSize;

    /**
     * 记录每个窗口的条数
     */
    private long size;

    public BitMapFilter() {
        this(4, 60 * 1000);
    }

    public BitMapFilter(int split, int slidingTime) {
        this.bitmap = new Roaring64Bitmap[split];
        for (int i = 0; i < split; i++) {
            bitmap[i] = new Roaring64Bitmap();
        }
        this.splitSize = new long[split];
        this.split = split;
        this.slidingTime = slidingTime;
    }

    public boolean isExist(long ptMsgId) {
        long now = getNow();
        int index = getIndex(now);
        return isExist(now, index, ptMsgId);
    }

    public long size() {
        return size;
    }


    private synchronized boolean isExist(long now, int index, long ptMsgId) {
        for (Roaring64Bitmap roaring64Bitmap : bitmap) {
            if (roaring64Bitmap.contains(ptMsgId)) {
                return true;
            }
        }
        clear(now, index);
        splitSize[index] ++;
        size++;
        bitmap[index].add(ptMsgId);
        return false;
    }

    private void clear(long now, int index) {
        if (now - this.index > split - 1) {
            size = size - splitSize[index];
            splitSize[index] = 0;
            bitmap[index].clear();
            this.index = now - split + 1;
        }
    }

    private long getNow() {
        return System.currentTimeMillis() / slidingTime;
    }

    private int getIndex(long now) {
        return (int) (now % split);
    }


}
